'use strict';

const Service = require('egg').Service;
const { generateSnowflakeId } = require('../utils/snowflake');

class MenuService extends Service {
  /**
   * 创建菜单
   * @param {Object} menuData - 菜单数据
   * @return {Promise<Object>}
   */
  async create(menuData) {
    const { ctx } = this;
    const menu = await ctx.model.Menu.create(menuData);
    return menu;
  }

  /**
   * 查询菜单列表
   * @param {Object} query - 查询条件
   * @param {number} page - 页码
   * @param {number} pageSize - 每页数量
   * @return {Promise<Object>}
   */
  async list(query, page = 1, pageSize = 10) {
    const { ctx } = this;
    const { name, type, status, visible } = query;
    const where = {};

    if (name) {
      where.name = { [ctx.app.Sequelize.Op.like]: `%${name}%` };
    }
    if (type) {
      where.type = type;
    }
    if (status !== undefined) {
      where.status = status === 'true';
    }
    if (visible !== undefined) {
      where.visible = visible === 'true';
    }

    const { count, rows } = await ctx.model.Menu.findAndCountAll({
      where,
      include: [
        {
          model: ctx.model.Menu,
          as: 'parent',
          attributes: ['id', 'name'],
        },
      ],
      order: [['sort', 'ASC'], ['id', 'ASC']],
      offset: (page - 1) * pageSize,
      limit: pageSize,
    });

    return {
      total: count,
      list: rows,
      page,
      pageSize,
    };
  }

  /**
   * 查询菜单树形结构
   * @param {Object} query - 查询条件
   * @return {Promise<Array>}
   */
  async tree(query) {
    const { ctx } = this;
    const { name, type, status, visible } = query;
    const where = {};

    if (name) {
      where.name = { [ctx.app.Sequelize.Op.like]: `%${name}%` };
    }
    if (type) {
      where.type = type;
    }
    if (status !== undefined && status !== '') {
      where.status = status === 'true' || status === true;
    }
    if (visible !== undefined && visible !== '') {
      where.visible = visible === 'true' || visible === true;
    }

    const menus = await ctx.model.Menu.findAll({
      where,
      include: [
        {
          model: ctx.model.Menu,
          as: 'parent',
          attributes: ['id', 'name'],
        },
      ],
      order: [['sort', 'ASC'], ['id', 'ASC']],
    });

    return this.buildTree(menus);
  }

  /**
   * 构建树形结构
   * @param {Array} menus - 菜单列表
   * @param {number} parentId - 父菜单ID
   * @return {Array}
   */
  buildTree(menus, parentId = 0) {
    const result = [];

    for (const menu of menus) {
      if (menu.parentId === parentId) {
        const children = this.buildTree(menus, menu.id);
        if (children.length > 0) {
          menu.dataValues.children = children;
        }
        result.push(menu);
      }
    }

    return result;
  }

  /**
   * 查询单个菜单
   * @param {string} id - 菜单ID
   * @return {Promise<Object>}
   */
  async findById(id) {
    const { ctx } = this;
    const menu = await ctx.model.Menu.findByPk(id, {
      include: [
        {
          model: ctx.model.Menu,
          as: 'parent',
          attributes: ['id', 'name'],
        },
      ],
    });
    return menu;
  }

  /**
   * 更新菜单
   * @param {string} id - 菜单ID
   * @param {Object} menuData - 菜单数据
   * @return {Promise<Object>}
   */
  async update(id, menuData) {
    const { ctx } = this;
    const menu = await ctx.model.Menu.findByPk(id);
    if (!menu) {
      throw new Error('菜单不存在');
    }
    await menu.update(menuData);
    return menu;
  }

  /**
   * 删除菜单
   * @param {string} id - 菜单ID
   * @return {Promise<void>}
   */
  async destroy(id) {
    const { ctx } = this;
    const menu = await ctx.model.Menu.findByPk(id);
    if (!menu) {
      throw new Error('菜单不存在');
    }

    // 检查是否有子菜单
    const children = await ctx.model.Menu.findAll({
      where: { parentId: id },
    });
    if (children.length > 0) {
      throw new Error('请先删除子菜单');
    }

    // 删除角色菜单关联
    await ctx.model.RoleMenu.destroy({
      where: { menuId: id },
    });

    await menu.destroy();
  }

  /**
   * 更新菜单状态
   * @param {string} id - 菜单ID
   * @param {boolean} status - 状态
   * @return {Promise<void>}
   */
  async updateStatus(id, status) {
    const { ctx } = this;
    const menu = await ctx.model.Menu.findByPk(id);
    if (!menu) {
      throw new Error('菜单不存在');
    }
    // 自动设置更新时间
    await menu.update({
      status,
      updateTime: new Date(),
    });
  }

  /**
   * 根据角色编码获取菜单列表
   * @param {string} roleCode - 角色编码
   * @return {Promise<Array>}
   */
  async getMenusByRoleCode(roleCode) {
    const { ctx } = this;

    // 先查询角色
    const role = await ctx.model.Role.findOne({
      where: { code: roleCode }
    });

    if (!role) {
      return [];
    }

    // 直接查询RoleMenu表，确认关联数据是否存在
    const roleMenuRecords = await ctx.model.RoleMenu.findAll({
      where: { roleCode: roleCode }
    });

    if (roleMenuRecords.length === 0) {
      return [];
    }

    // 查询角色关联的菜单
    const roleWithMenus = await ctx.model.Role.findOne({
      where: { code: roleCode },
      include: [
        {
          model: ctx.model.Menu,
          as: 'menus',
          through: { attributes: [] },
          include: [
            {
              model: ctx.model.Menu,
              as: 'parent',
              attributes: ['id', 'name'],
            },
          ],
          order: [['sort', 'ASC'], ['id', 'ASC']],
        },
      ],
    });

    return roleWithMenus.menus || [];
  }

  /**
   * 根据角色编码获取菜单树形结构
   * @param {string} roleCode - 角色编码
   * @return {Promise<Object>}
   */
  async getMenuTreeByRoleCode(roleCode) {
    const { ctx } = this;

    // 获取所有菜单树
    const allMenus = await this.tree({});

    // 获取角色已分配的菜单ID
    const roleMenus = await this.getMenusByRoleCode(roleCode);
    const checkedKeys = roleMenus.map(menu => menu.id);

    return {
      menus: allMenus,
      checkedKeys: checkedKeys
    };
  }

  /**
   * 为角色分配菜单
   * @param {string} roleCode - 角色编码
   * @param {Array} menuIds - 菜单ID数组
   * @return {Promise<void>}
   */
  async assignMenusToRoleCode(roleCode, menuIds) {
    const { ctx } = this;
    const role = await ctx.model.Role.findOne({
      where: { code: roleCode }
    });
    if (!role) {
      throw new Error('角色不存在');
    }

    // 删除原有关联
    await ctx.model.RoleMenu.destroy({
      where: { roleCode: roleCode },
    });

    // 创建新关联
    const roleMenus = menuIds.map(menuId => ({
      id: generateSnowflakeId(),
      roleCode: roleCode,
      menuId: menuId,
    }));

    if (roleMenus.length > 0) {
      await ctx.model.RoleMenu.bulkCreate(roleMenus);
    }
  }

  /**
   * 获取用户菜单列表
   * @param {string} userId - 用户ID
   * @return {Promise<Array>}
   */
  async getUserMenus(userId) {
    const { ctx } = this;

    // 先查询用户角色（不包含菜单）
    const user = await ctx.model.User.findByPk(userId, {
      include: [
        {
          model: ctx.model.Role,
          as: 'roles',
          through: { attributes: [] },
        },
      ],
    });

    if (!user || !user.roles || user.roles.length === 0) {
      return [];
    }

    // 获取所有角色编码
    const roleCodes = user.roles.map(role => role.code);

    // 查询这些角色的菜单
    const roleMenus = await ctx.model.RoleMenu.findAll({
      where: { roleCode: roleCodes },
      include: [
        {
          model: ctx.model.Menu,
          as: 'menu',
          where: { status: true, visible: true },
          include: [
            {
              model: ctx.model.Menu,
              as: 'parent',
              attributes: ['id', 'name'],
            },
          ],
          order: [['sort', 'ASC'], ['id', 'ASC']],
        },
      ],
    });

    // 如果roleMenus为空，尝试直接查询菜单表
    if (roleMenus.length === 0) {
      const allMenus = await ctx.model.Menu.findAll({
        where: { status: true, visible: true },
        include: [
          {
            model: ctx.model.Menu,
            as: 'parent',
            attributes: ['id', 'name'],
          },
        ],
        order: [['sort', 'ASC'], ['id', 'ASC']],
      });
      return allMenus;
    }

    // 收集所有菜单
    const allMenus = [];
    const menuSet = new Set();

    for (const roleMenu of roleMenus) {
      if (roleMenu.menu && !menuSet.has(roleMenu.menu.id)) {
        allMenus.push(roleMenu.menu);
        menuSet.add(roleMenu.menu.id);
      }
    }

    // 对菜单数组进行排序
    allMenus.sort((a, b) => {
      if (a.sort !== b.sort) {
        return a.sort - b.sort;
      }
      return a.id - b.id;
    });

    return allMenus;
  }

  /**
   * 获取用户菜单树形结构
   * @param {string} userId - 用户ID
   * @return {Promise<Array>}
   */
  async getUserMenuTree(userId) {
    const menus = await this.getUserMenus(userId);
    return this.buildTree(menus);
  }
}

module.exports = MenuService;